package cn.juque.luceneplus.init;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.juque.common.exception.AppException;
import cn.juque.luceneplus.constants.BasicIndexFieldEnum;
import cn.juque.luceneplus.constants.IndexEnum;
import cn.juque.luceneplus.constants.LuceneConfig;
import cn.juque.luceneplus.constants.LuceneMsgEnum;
import cn.juque.luceneplus.dto.FieldTemplateDTO;
import cn.juque.luceneplus.dto.IndexTemplateDTO;
import cn.juque.luceneplus.service.IndexPlusService;
import com.alibaba.fastjson.JSON;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.document.Document;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

/**
 * @author nuoka
 * @version 1.0.0
 * <li>IntelliJ IDEA</li>
 * <li></li>
 * @date 2021/10/4 11:27
 **/
@Slf4j
@Component
public class LuceneInitialization implements ApplicationRunner {

    @Value("${lucene.index.template.path}")
    private String templatePath;

    @Resource
    private IndexPlusService indexPlusService;

    /**
     * Callback used to run the bean.
     *
     * @param args incoming application arguments
     * @throws Exception on error
     */
    @Override
    public void run(ApplicationArguments args) throws Exception {
        this.init();
    }

    /**
     * 初始化索引信息
     *
     * @throws IOException IOException
     */
    private void init() throws IOException {
        // 获取所有父类的子类
        List<String> templateList = this.getTemplate();
        if(CollUtil.isEmpty(templateList)) {
            return;
        }
        for (String t : templateList) {
            log.info("found index template:{}", t);
            IndexTemplateDTO indexTemplateDTO = JSON.parseObject(t, IndexTemplateDTO.class);
            // 校验系统占用标识
            this.existSystemField(indexTemplateDTO);
            List<FieldTemplateDTO> fieldTemplateDTOList = indexTemplateDTO.getFieldDTOList();
            if (CollUtil.isEmpty(fieldTemplateDTOList)) {
                return;
            }
            List<Document> list = this.indexPlusService.getIndexInfo(indexTemplateDTO.getIndexName());
            if (list.size() + fieldTemplateDTOList.size() > LuceneConfig.FIELD_MAX_COUNT) {
                throw new AppException(LuceneMsgEnum.FIELD_NUM_MAX_LIMIT);
            }
            Map<String, Document> docMap = MapUtil.newHashMap();
            list.forEach(doc -> docMap.put(doc.get(BasicIndexFieldEnum.FIELD_NAME.getValue()), doc));
            // 不存在则初始化基础索引
            List<FieldTemplateDTO> initFieldList = fieldTemplateDTOList.stream()
                .filter(f -> !docMap.containsKey(f.getFieldName())).collect(
                    Collectors.toList());
            indexTemplateDTO.setFieldDTOList(initFieldList);
            this.indexPlusService.initBasicIndex(indexTemplateDTO);
        }
    }

    /**
     * 获取所有的索引的模板
     * @return 索引模板
     */
    private List<String> getTemplate() {
        File[] files = FileUtil.ls(this.templatePath);
        if(ArrayUtil.isEmpty(files)) {
            return CollUtil.newArrayList();
        }
        return Arrays.stream(files).map(t->FileUtil.readString(t, Charset.defaultCharset())).collect(Collectors.toList());
    }
    /**
     * 是否存在系统占用的字段
     * @param indexTemplateDTO 索引信息
     */
    private void existSystemField(IndexTemplateDTO indexTemplateDTO) {
        Boolean flag = IndexEnum.BASIC_INDEX.getName().equals(indexTemplateDTO.getIndexName());
        if(Boolean.TRUE.equals(flag)) {
            throw new AppException(LuceneMsgEnum.BASIC_INDEX_BELONG_SYSTEM_FIELD);
        }
        List<FieldTemplateDTO> fieldTemplateDTOList = indexTemplateDTO.getFieldDTOList();
        flag = fieldTemplateDTOList.stream().anyMatch(t->IndexEnum.TIMESTAMP.getName().equals(t.getFieldName()));
        if(Boolean.TRUE.equals(flag)) {
            throw new AppException(LuceneMsgEnum.TIMESTAMP_BELONG_SYSTEM_FIELD);
        }
    }
}
